package xcmg.device.service.account;

import com.github.pagehelper.PageInfo;
import yb.ecp.fast.infra.util.PageHelperPlus;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import xcmg.device.dao.entity.account.InvoiceDO;
import xcmg.device.dao.entity.account.InvoiceDetailDO;
import xcmg.device.dao.entity.company.CompanyDealerDO;
import xcmg.device.dao.entity.company.CompanyInfoDO;
import xcmg.device.dao.entity.delivery.DeliveryNoteDO;
import xcmg.device.dao.mapper.CompanyDealerMapper;
import xcmg.device.dao.mapper.CompanyInfoMapper;
import xcmg.device.dao.mapper.account.InvoiceDetailMapper;
import xcmg.device.dao.mapper.account.InvoiceMapper;
import xcmg.device.dao.mapper.delivery.DeliveryNoteMapper;
import xcmg.device.infra.DateUtil;
import xcmg.device.infra.ErrorCode;
import xcmg.device.infra.ExportUtil;
import xcmg.device.service.vo.account.InvoiceDetailVO;
import xcmg.device.service.vo.account.InvoiceVO;
import yb.ecp.fast.feign.FastGenClient;
import yb.ecp.fast.infra.infra.ActionResult;
import yb.ecp.fast.infra.infra.PageCommonVO;
import yb.ecp.fast.infra.infra.SearchCommonVO;
import yb.ecp.fast.infra.infra.log.LogHelper;
import yb.ecp.fast.infra.util.ListUtil;
import yb.ecp.fast.infra.util.StringUtil;

import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;

@Service
public class InvoiceService {

    @Autowired
    private FastGenClient fastGenClient;

    @Autowired
    private CompanyInfoMapper companyInfoMapper;

    @Autowired
    private InvoiceMapper invoiceMapper;

    @Autowired
    private InvoiceDetailMapper invoiceDetailMapper;

    @Autowired
    private CompanyDealerMapper companyDealerMapper;

    @Autowired
    private ArapService arapService;

    @Autowired
    private HttpServletResponse response;

    @Autowired
    private DeliveryNoteMapper deliveryNoteMapper;

    /**
     * 发货通知单开票状态：0未开票，1已开票
     */
    private static final Integer TICKET_STATUS_NO = 0, TICKET_STATUS_YES = 1;

    /**
     * 删除标记。0未删除，1已删除
     */
    private static final Integer DELETE_FLAG_NO = 0, DELETE_FLAG_YES = 1;

    @Transactional(rollbackFor = Exception.class)
    public List<Map<String, String>> addInvoice(List<Map<String, String>> dataList, CompanyInfoDO companyInfoDO)throws Exception{
        if(ListUtil.isNullOrEmpty(dataList)){
            return null;
        }
        boolean isDel;
        InvoiceDO invoiceDO;
        CompanyDealerDO dealerDO;
        String invoiceNo;
        String dealerCode;
        String orgId = companyInfoDO.getOrgId();
        List<Map<String, String>> list = new ArrayList<>();
        Map<String,Integer> countDetail=new HashMap<>();
        SimpleDateFormat sdf = new SimpleDateFormat("EEE MMM dd HH:mm:ss z yyyy", Locale.ENGLISH);
        for(Map<String, String> dataMap : dataList){
            isDel = "X".equals(dataMap.get("VBELN_VF_FLAG"));
            if(!isDel){
                list.add(dataMap);
            }
            invoiceNo = dataMap.get("VBELN_VF");
            if(countDetail.get(invoiceNo)!=null){
                isDel=countDetail.get(invoiceNo)<=0;
            }else {
                int detailCount=invoiceDetailMapper.countDeliveryNo(invoiceNo,orgId);
                isDel=detailCount<=0;
                countDetail.put(invoiceNo,detailCount);
            }
            dealerCode = dataMap.get("KUNRG");
            if(StringUtil.isNullOrEmpty(invoiceNo)){
                LogHelper.monitor("开票凭证为空");
                continue;
            }
            dealerDO = companyDealerMapper.itemByDealerCode(orgId, dealerCode);
            if(dealerDO == null){
                LogHelper.monitor("付款方 (客户编码)不存在，"+dealerCode);
                continue;
            }

            invoiceDO = invoiceMapper.selectByInvoiceNo(invoiceNo, orgId);
            if(!isDel && invoiceDO == null){
                invoiceDO = new InvoiceDO();
                invoiceDO.setId(fastGenClient.textGuid().getValue());
                invoiceDO.setInvoiceNo(invoiceNo);
                invoiceDO.setInvoicePaperNo(dataMap.get("SGTXT"));
                invoiceDO.setPrice(new BigDecimal(dataMap.get("DMBTR")));
                invoiceDO.setPayerOrgId(dealerDO.getDealerOrgId());
                invoiceDO.setPayerOrgName(dealerDO.getCompanyName());
                invoiceDO.setPayerSapCode(dealerCode);
                invoiceDO.setOrgId(orgId);
                invoiceDO.setSapCode(companyInfoDO.getSapCode());
                invoiceDO.setOrgName(companyInfoDO.getCompanyName());
                invoiceDO.setOrderDate(sdf.parse(dataMap.get("FKDAT")));
                invoiceDO.setPostDate(sdf.parse(dataMap.get("ERDAT")));
                invoiceDO.setCreateDate(new Date());
                invoiceMapper.insert(invoiceDO);
            }else if(isDel && invoiceDO != null && invoiceDO.getIsDel() == 0){
                //执行发票作废操作
                invoiceDO.setIsDel(1);
                boolean success = invoiceMapper.update(invoiceDO)>0;
                if(success){
                    arapService.cancel(invoiceDO);
                }

            }        }
        return list;
    }

    @Transactional(rollbackFor = Exception.class)
    public List<Map<String, String>> addInvoiceDetail(List<Map<String, String>> dataList, String orgId)throws Exception{
        if(ListUtil.isNullOrEmpty(dataList)){
            return null;
        }
        InvoiceDetailDO detailDO;
        InvoiceDetailVO detailVO = new InvoiceDetailVO();
        List<InvoiceDetailDO> invoiceDetailDOList;
        List<Map<String, String>> list = new ArrayList<>();
        SimpleDateFormat sdf = new SimpleDateFormat("EEE MMM dd HH:mm:ss z yyyy", Locale.ENGLISH);
        List<String> sapDeliveryNos = new ArrayList<>();
        for(Map<String, String> dataMap : dataList){
            detailDO = new InvoiceDetailDO();
            detailDO.setId(fastGenClient.textGuid().getValue());
            detailDO.setInvoiceNo(dataMap.get("VBELN_VF"));
            detailDO.setInvoicePaperNo(dataMap.get("SGTXT"));

            String deliveryNo = dataMap.get("JHDANCODE");

            detailDO.setDeliveryNo(deliveryNo);
            detailDO.setDeliveryProNo(dataMap.get("JHPOSNR"));
            detailDO.setSaleDistNo(dataMap.get("VBELN"));
            detailDO.setSaleDistProNo(dataMap.get("POSNR"));
            detailDO.setAccountNo(dataMap.get("BELNR"));
            detailDO.setAccountRowNo(dataMap.get("BUZEI"));
            detailDO.setMaterialsNo(dataMap.get("MATNR"));
            detailDO.setOutMaterialsGroup(dataMap.get("EXTWG"));
            detailDO.setSerialNo(dataMap.get("SERNR"));
            detailDO.setUnitPrice(new BigDecimal(dataMap.get("KZWI1")==null?"0":dataMap.get("KZWI1")));
            detailDO.setTotalPrice(new BigDecimal(dataMap.get("DMBTR")==null?"0":dataMap.get("DMBTR")));
            detailDO.setOrderDate(sdf.parse(dataMap.get("FKDAT")));
            detailDO.setPostDate(sdf.parse(dataMap.get("ERDAT")));

            boolean deleteFlag = "X".equals(dataMap.get("VBELN_VF_FLAG"));
            detailDO.setIsDel(deleteFlag ? DELETE_FLAG_YES : DELETE_FLAG_NO);
            detailDO.setCreateDate(new Date());
            detailDO.setOrgId(orgId);

            BeanUtils.copyProperties(detailDO, detailVO);
            invoiceDetailDOList =  invoiceDetailMapper.list(detailVO);
            if(!ListUtil.isNullOrEmpty(invoiceDetailDOList)){
                LogHelper.monitor("该条发票记录已存在，"+invoiceDetailDOList.get(0).getId());
                continue;
            }
            saveOrUpdateDetails(detailDO);
            list.add(dataMap);

            //2019-3-22 一个发票对应多个发票明细，多个明细可能发货通知单号一样，可能只需要更新一次，如果不做判断可能会执行多次重复的更新
            if (!sapDeliveryNos.contains(deliveryNo)) {
                updateDeliveryNote(deliveryNo, orgId, deleteFlag);
                sapDeliveryNos.add(deliveryNo);
            }

        }
        return list;
    }

    /**
     * 保存或者更新发票明细数据
     *
     * @param detailDO
     */
    private void saveOrUpdateDetails(InvoiceDetailDO detailDO) {
        List<InvoiceDetailDO> detailDBS = invoiceDetailMapper.listByMaterialsNo(detailDO.getInvoiceNo(),detailDO.getDeliveryNo(), detailDO.getDeliveryProNo(), detailDO.getMaterialsNo(), detailDO.getOrgId());
        if (CollectionUtils.isEmpty(detailDBS)) {
            invoiceDetailMapper.insert(detailDO);
            return;
        }
        // 以上条件查询出来的结果，如果只有一条，直接更新，如果有多条一定是存在在重复的脏数据，多余的删除
        invoiceDetailMapper.update(detailDBS.get(0));
        if (detailDBS.size() == 1) {
            return;
        }
        for (int i = 1; i < detailDBS.size(); i++) {
            invoiceDetailMapper.deleteByPrimaryKey(detailDBS.get(i).getId());
        }
    }


    /**
     * 修改对应发货通知单的开票状态
     *
     * @param sapDeliveryNo
     * @param orgId
     * @param deleteFlag
     */
    private void updateDeliveryNote(String sapDeliveryNo, String orgId, boolean deleteFlag) {
        DeliveryNoteDO deliveryNoteDO = deliveryNoteMapper.findBySapOutNo(sapDeliveryNo, orgId);
        if (null == deliveryNoteDO) {
            return;
        }
        deliveryNoteDO.setTicketState(deleteFlag ? TICKET_STATUS_NO : TICKET_STATUS_YES);
        deliveryNoteMapper.update(deliveryNoteDO);
    }

    public ErrorCode sign(InvoiceVO invoiceVO){
        if(StringUtil.isNullOrEmpty(invoiceVO.getId()) || StringUtil.isNullOrEmpty(invoiceVO.getSignNote()) ){
            return ErrorCode.IllegalArument;
        }
        InvoiceDO invoiceDO = new InvoiceDO();
        BeanUtils.copyProperties(invoiceVO, invoiceDO);
        invoiceDO.setSignDate(new Date());
        invoiceDO.setIsSign(1);
        return invoiceMapper.update(invoiceDO)>0?ErrorCode.Success:ErrorCode.Failure;
    }

    public PageCommonVO list(SearchCommonVO<InvoiceVO> condition, String orgId) {
        filterOrgId(condition.getFilters(), orgId);
        PageCommonVO result = new PageCommonVO();
        PageHelperPlus.orderBy("create_date desc");
        PageHelperPlus.startPage(condition.getPageNum(), condition.getPageSize());
        List<InvoiceDO> doList = invoiceMapper.list(condition.getFilters());
        List<InvoiceVO> voList = new ArrayList<>();
        for (InvoiceDO entity : doList) {
            InvoiceVO model = new InvoiceVO();
            BeanUtils.copyProperties(entity, model);
            voList.add(model);
        }
        result.setPageInfo(new PageInfo(doList));
        result.setPageInfoList(voList);
        return result;
    }

    private void filterOrgId(InvoiceVO invoiceVO, String orgId) {
        CompanyInfoDO infoDO = companyInfoMapper.item(orgId);
        if (infoDO == null) {
            return;
        }
        if (infoDO.getIsSap() != null && infoDO.getIsSap() == 1) {
            invoiceVO.setOrgId(orgId);
        } else {
            List<String> dealerOrgIds = companyDealerMapper.findDealerOrgIds(orgId);
            if (dealerOrgIds == null) {
                dealerOrgIds = new ArrayList<>();
            }
            dealerOrgIds.add(orgId);
            invoiceVO.setDealerOrgIds(dealerOrgIds);
        }
    }

    public PageCommonVO detailList(SearchCommonVO<InvoiceDetailVO> condition) {
        PageCommonVO result = new PageCommonVO();
        PageHelperPlus.orderBy("CREATE_DATE desc");
        PageHelperPlus.startPage(condition.getPageNum(), condition.getPageSize());
        condition.getFilters().setIsDel(0);
        List<InvoiceDetailDO> doList = invoiceDetailMapper.list(condition.getFilters());
        List<InvoiceDetailVO> voList = new ArrayList<>();
        for (InvoiceDetailDO entity : doList) {
            InvoiceDetailVO model = new InvoiceDetailVO();
            BeanUtils.copyProperties(entity, model);
            voList.add(model);
        }
        result.setPageInfo(new PageInfo(doList));
        result.setPageInfoList(voList);
        return result;
    }

    public void export(List<String> ids)throws Exception{
        invokeExport(invoiceMapper.findByIds(ids));
    }

    public void exportAll(InvoiceVO condition, String orgId)throws Exception{
        filterOrgId(condition, orgId);
        Integer count = invoiceMapper.listCount(condition);
        List<InvoiceDO> dataList = new ArrayList<>();
        int times = count/500+1;
        for(int i=0; i<times; i++){
            PageHelperPlus.startPage(i + 1, 500, "create_date desc");
            dataList.addAll(invoiceMapper.list(condition));
        }
        invokeExport(dataList);
    }

    private void invokeExport(List<InvoiceDO> doList)throws Exception{
        String title = "发票数据导出";
        String[] rowsName = new String[]{"序号","开票凭证","纸质发票号","票据金额","付款方",
                "单据创建时间", "过账时间", "创建时间", "签收人", "签收说明", "签收时间"};
        List<Object[]>  dataList = new ArrayList<>();
        Object[] objs;
        for (int i = 0; i < doList.size(); i++) {
            InvoiceDO exportDO = doList.get(i);
            objs = new Object[rowsName.length];
            objs[0] = i+1;
            objs[1] = exportDO.getInvoiceNo();
            objs[2] = exportDO.getInvoicePaperNo();
            objs[3] = exportDO.getPrice();
            objs[4] = exportDO.getPayerOrgName();
            objs[5] = DateUtil.formatDateTime(exportDO.getOrderDate());
            objs[6] = DateUtil.formatDateTime(exportDO.getPostDate());
            objs[7] = DateUtil.formatDateTime(exportDO.getCreateDate());
            objs[8] = exportDO.getSignName();
            objs[9] = exportDO.getSignNote();
            objs[10] = DateUtil.formatDateTime(exportDO.getSignDate());
            dataList.add(objs);
        }
        ExportUtil exportUtil = new ExportUtil(title, rowsName, dataList);
        exportUtil.export(response);
    }

    @Transactional
    public ActionResult update(InvoiceVO invoiceVO) {
        ActionResult result = new ActionResult();
        if (StringUtils.isBlank(invoiceVO.getId())) {
            result.setCode(ErrorCode.IllegalArument.getCode());
        }
        InvoiceDO invoiceDO = new InvoiceDO();
        BeanUtils.copyProperties(invoiceVO, invoiceDO);
        if (null == invoiceVO.getInvoicePaperNo()) {
            invoiceDO.setInvoicePaperNo(StringUtils.EMPTY);
        }
        invoiceMapper.update(invoiceDO);
        result.setCode(ErrorCode.Success.getCode());
        return result;
    }

    public InvoiceVO getById(String id) {
        InvoiceVO invoiceVO = new InvoiceVO();
        InvoiceDO invoiceDO = invoiceMapper.selectByPrimaryKey(id);
        BeanUtils.copyProperties(invoiceDO, invoiceVO);
        InvoiceDetailVO condition = new InvoiceDetailVO();
        condition.setInvoiceNo(invoiceDO.getInvoiceNo());
        condition.setOrgId(invoiceDO.getOrgId());
        List<InvoiceDetailDO> detailDOs = invoiceDetailMapper.list(condition);

        List<InvoiceDetailVO> detailVOS = new ArrayList<>();
        for (InvoiceDetailDO detailDO : detailDOs) {
            InvoiceDetailVO detailVO = new InvoiceDetailVO();
            BeanUtils.copyProperties(detailDO, detailVO);
            detailVOS.add(detailVO);
        }
        invoiceVO.setDetailVOList(detailVOS);
        return invoiceVO;
    }
}